#include <iostream>
#include <queue>
#include <pthread.h>

using namespace std;

template <class T>
class BlocQueue
{
    static const u_int32_t default_capacity = 10;

    bool isExternalSignal()
    {
        pthread_mutex_lock(&_signal_mutex); //保护is_external_signal
        bool tmp=_is_external_signal==true;
        pthread_mutex_unlock(&_signal_mutex); 

        return tmp;
    }
public:
    BlocQueue(int c = default_capacity)
        : _capacity(c),
          _cwait(0),
          _pwait(0),
          _is_external_signal(false)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_mutex_init(&_size_mutex, nullptr);
        pthread_mutex_init(&_signal_mutex, nullptr);

        pthread_cond_init(&_ccond, nullptr);
        pthread_cond_init(&_pcond, nullptr);
    }
    bool Push(const T &in) // 生产
    {
        pthread_mutex_lock(&_mutex);

        while (isFull()) // 如果阻塞队列满了
        {
            if(isExternalSignal())//如果外部唤醒了
            {
                pthread_mutex_unlock(&_mutex);
                return false;//线程退出该函数
            }
            _pwait++;
            pthread_cond_wait(&_pcond, &_mutex); // 阻塞等待
            _pwait--;
        }
        pthread_mutex_lock(&_size_mutex); // 保护阻塞队列的size

        _q.push(in); // 生产数据

        pthread_mutex_unlock(&_size_mutex);

        if (_cwait > 0)
            pthread_cond_broadcast(&_ccond); // 唤醒消费者线程

        pthread_mutex_unlock(&_mutex);

        return true;
    }
    bool Pop(T &out) // 消费
    {
        pthread_mutex_lock(&_mutex);

        while (isEmpty()) // 如果阻塞队列为空
        {
            if(isExternalSignal())//如果外部唤醒了
            {
                pthread_mutex_unlock(&_mutex);
                return false;//线程退出该函数
            }
            _cwait++;
            pthread_cond_wait(&_ccond, &_mutex); // 阻塞等待
            _cwait--;
        }
        pthread_mutex_lock(&_size_mutex); // 保护阻塞队列的size
        // 消费数据
        out = _q.front();
        _q.pop();
        pthread_mutex_unlock(&_size_mutex);

        if (_pwait > 0)
            pthread_cond_broadcast(&_pcond); // 唤醒生产者线程

        pthread_mutex_unlock(&_mutex);

        return true;
    }

    bool isFull()
    {
        pthread_mutex_lock(&_size_mutex); // 保护阻塞队列的size
        bool tmp = _q.size() == _capacity;
        pthread_mutex_unlock(&_size_mutex); // 保护阻塞队列的size

        return tmp;
    }
    bool isEmpty()
    {
        pthread_mutex_lock(&_size_mutex); // 保护阻塞队列的size
        bool tmp=_q.size()==0;
        pthread_mutex_unlock(&_size_mutex); // 保护阻塞队列的size
        return tmp;
    }
    void ExternalSignal()//进入外部唤醒状态
    {
        pthread_mutex_lock(&_signal_mutex); //保护is_external_signal
        _is_external_signal=true;
        
        pthread_cond_broadcast(&_pcond); // 唤醒生产者线程
        pthread_cond_broadcast(&_ccond); // 唤醒消费者线程

        pthread_mutex_unlock(&_signal_mutex); 
    }
    void CancelExternalSignal()//取消外部唤醒状态
    {
        pthread_mutex_lock(&_signal_mutex); //保护is_external_signal
        _is_external_signal=false;
        pthread_mutex_unlock(&_signal_mutex); 
    }

    ~BlocQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_mutex_destroy(&_size_mutex);
        pthread_mutex_destroy(&_signal_mutex);

        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }

private:
    queue<T> _q;             // 阻塞队列
    u_int32_t _capacity;     // 队列容量
    bool _is_external_signal; // 是否需要外部唤醒

    pthread_mutex_t _mutex;      // 锁,保护阻塞队列
    pthread_mutex_t _size_mutex; // 锁，保护阻塞队列的size
    pthread_mutex_t _signal_mutex; // 锁，保护is_external_signal

    pthread_cond_t _pcond; // 生产者条件变量
    pthread_cond_t _ccond; // 消费者条件变量
    u_int32_t _pwait;      // 生产者条件变量下阻塞等待的线程个数
    u_int32_t _cwait;      // 消费者条件变量下阻塞等待的线程个数
};
